﻿namespace egret3d
{
    export class MeshBatcher
    {
        private _mesh: Mesh;

        public get mesh()
        {
            return this._mesh;
        }

        private _vercount: number;
        public get vercount()
        {
            return this._vercount;
        }
        private _indexcount: number;
        public get indexcount()
        {
            return this._indexcount;
        }
        public parlist: Array<Particle>;

        public active: boolean;
        private _maxvercount: number = 4096;
        public get maxvercount()
        {
            return this._maxvercount;
        }
        constructor(_mesh: Mesh)
        {
            this.active = true;

            this._mesh = _mesh;

            this.mesh.geometry.vertexFormat = VertexFormat.VF_POSITION | VertexFormat.VF_NORMAL | VertexFormat.VF_TANGENT | VertexFormat.VF_COLOR | VertexFormat.VF_UV0;
            this.mesh.geometry.vertexCount = 0;
            this.mesh.geometry.indexCount = 0;

            this.parlist = new Array<Particle>();
            this._vercount = 0;
            this._indexcount = 0;
            
            ////直接准备好数据
            this.mesh.geometry.vertexArray = new Float32Array(15 * 4096);
            this.mesh.geometry.indexArray = new Uint16Array(3 * 4096);
            ////生成一次数据
            this.mesh.geometry.upload(Egret3DCanvas.context3DProxy, Context3DProxy.gl.DYNAMIC_DRAW);

            this.mesh.geometry.vertexArray = null;
            this.mesh.geometry.indexArray = null;
        }

        AddP(particle: Particle)
        {
            for (var i = 0; i < particle.shape.vertexCount; i++)
            {
                var v = particle.shape.getVertexForIndex(i);
                for (var j = 0; j < v.length; j++)
                {
                    this.mesh.geometry.sharedVertexBuffer.arrayBuffer[(this._vercount + i) * v.length + j] = v[j];
                }
            }
            for (var i = 0; i < particle.shape.indexArray.length; i++)
            {
                this.mesh.geometry.sharedIndexBuffer.arrayBuffer[this._indexcount + i] = particle.shape.indexArray[i] + this._vercount;
            }

            this._vercount += particle.shape.vertexCount;
            this._indexcount += particle.shape.indexCount;


            this.mesh.geometry.vertexCount = this._vercount;

            this.mesh.geometry.indexCount = this._indexcount;

            this.parlist.push(particle);

            this.mesh.geometry.bufferDiry = true;
        }
        //AddParticle(key: string, shapeCount: number): Particle
        //{
        //    var particle = new Particle(MeshBatcherMgr.instance().getshape(key), shapeCount);
        //    if (particle != null)
        //    {
        //        this.AddP(particle);
        //    }
        //    return particle;
        //}
        AddParticleByShape(particleShape: ParticleShape, shapeCount: number): Particle
        {
            var particle = new Particle(particleShape, shapeCount);
            if (particle != null)
            {
                this.AddP(particle);
            }
            return particle;
        }
        update(delta: number)
        {
            if (!this.active) return;
            var _active = false;
            var vertexindex = 0;
            for (var n = 0; n < this.parlist.length; n++)
            {
                var particle = this.parlist[n];
                if (!particle.updatelifetime(delta))
                {
                    if (particle.isloop)
                    {
                        _active = true;
                    }
                }
                else
                {
                    _active = true;
                }
                for (var i = 0; i < particle.shape.vertexCount; i++)
                {
                    var v = particle.shape.getVertexForIndex(i);

                    var vec3 = new Vector3D(v[0], v[1], v[2]);
                    //坐标变换
                    var nvec3 = particle.matrix.transformVector(vec3);

                    this.mesh.geometry.sharedVertexBuffer.arrayBuffer[(vertexindex + i) * this.mesh.geometry.vertexAttLength + 0] = nvec3.x;
                    this.mesh.geometry.sharedVertexBuffer.arrayBuffer[(vertexindex + i) * this.mesh.geometry.vertexAttLength + 1] = nvec3.y;
                    this.mesh.geometry.sharedVertexBuffer.arrayBuffer[(vertexindex + i) * this.mesh.geometry.vertexAttLength + 2] = nvec3.z;
                }
                vertexindex += particle.shape.vertexCount;

            }
            this.active = _active;
            this.mesh.geometry.bufferDiry = true;
        }
        bdispose: boolean = false;
        dispose()
        {
            if (this.mesh != null)
            {
                if (!this.bdispose)
                {
                    this.mesh.dispose();
                    this.bdispose = true;
                }
            }
        }
    }
    export class Particle
    {
        isinit: boolean;
        shape: ParticleShape;

        matrix: Matrix4_4;
        shapeID: number;

        posDir: Vector3D;
        pos: Vector3D;

        scaleVec: Vector3D;

        rotDir: Vector3D;
        anglenum: number;

        private _alive: boolean;
        lifeTime: number;
        curlifeTime: number;
        isloop: boolean;

        constructor(_shape: ParticleShape, _shapeID: number)
        {
            this.matrix = new Matrix4_4();
            this.shape = _shape;
            this.shapeID = _shapeID;
            this.posDir = new Vector3D(1, 1, 0);
            this.pos = new Vector3D(0, 0, 0);

            this.scaleVec = new Vector3D(1, 1, 1);

            this.rotDir = new Vector3D(0, 1, 0);
            this.anglenum = 0;

            this._alive = true;
            this.lifeTime = 2;
            this.curlifeTime = 0;
            this.isloop = false;

            this.isinit = false;
        }

        
        public clear()
        {
            this.matrix.identity();
            this.curlifeTime = 0;
            this._alive = true;
            this.pos = new Vector3D(0, 0, 0);
            this.anglenum = 0;
        }

        public updatelifetime(deltaTime: number): boolean
        {
            if (!this._alive)
            {
                return this._alive;
            }

            this.curlifeTime += deltaTime;
            if (this.curlifeTime > this.lifeTime)
            {
                this._alive = false;
            }
            return this._alive;
        }

        public get alive()
        {
            return this._alive;
        }

        public set alive(value: boolean)
        {
            this._alive = value;
        }
    }
    export class MeshBatcherMgr
    {
        private static _this: MeshBatcherMgr;
        private mapShape: { [id: string]: ParticleShape };

        constructor()
        {
            this.mapShape = {};
            this.regbaseshape();
        }

        static instance(): MeshBatcherMgr
        {
            if (MeshBatcherMgr._this == null)
                MeshBatcherMgr._this = new MeshBatcherMgr();
            return MeshBatcherMgr._this;
        }

        regbaseshape()
        {
            this.mapShape["cube"] = new CubeShape(100, 100, 100);
            this.mapShape["sphere"] = new SphereShape();
            this.mapShape["plane"] = new PlaneShape();
        }

        regshape(key: string, value: ParticleShape)
        {
            this.mapShape[key] = value;
        }
        getshape(key: string)
        {
            if (this.mapShape == null)
            {
                throw new Error(key + " is not reg");
            }
            return this.mapShape[key];
        }
    }
}